package board;

import player.Move;
import list.ArrayList;

/**
 * The Player's internal representation of a game board
 * 
 */
public class Board {

	 final Piece[][] board;
	 final ArrayList<Piece> blackPieces; // used in DepthFirstSearch's eval.
	 final ArrayList<Piece> whitePieces; // used in DepthFirstSearch's eval.

	public Board() {
		blackPieces = new ArrayList<Piece>();
		whitePieces = new ArrayList<Piece>();
		board = new Piece[8][8];
		// populate the board with empty pieces
		for (int x = 0; x < board.length; x++) {
			for (int y = 0; y < board[0].length; y++) {
				board[x][y] = Piece.makeEmptyPiece(x, y);
			}
		}
	}

	/**
	 * Returns the side length of the board (should be 8)
	 */
	public int getLength(){
		return board.length;
	}
	
	/**
	 * Returns a list of the black pieces in this board.
	 */
	public ArrayList<Piece> getBlackPieces(){
		return blackPieces;
	}
	
	/**
	 * Returns a list of the white pieces in this board.
	 */
	public ArrayList<Piece> getWhitePieces(){
		return whitePieces;
	}
	
	/**
	 * Returns the piece occupying x,y
	 * 
	 * @param x
	 * @param y
	 * @return
	 */
	public Piece pieceAt(int x, int y) {
		return board[x][y];
	}

	/**
	 * Returns whether a move is legal
	 * 
	 * @param m
	 * @param color
	 * @return
	 */
	public boolean isLegal(Move m, int color) {
		if (m.moveKind == Move.QUIT) {
			return true;
			//throw new RuntimeException("QUIT not implemented");
		} else if (m.moveKind == Move.STEP) { // STEP move
			//System.out.println("step move: "+m);
			if (board[m.x2][m.y2].color != color) { // if you are trying to step
													// a piece that is not yours
				return false;
			}
			Piece oldpiece = board[m.x2][m.y2];
			clearSpot(m.x2, m.y2);
			Move temp = new Move(m.x1, m.y1);
			boolean b = isLegal(temp, color);
			board[m.x2][m.y2] = oldpiece;
			return b;
		} else { // ADD move
			int x = m.x1;
			int y = m.y1;
			// check if it is within bounds
			if (x > 7 || x < 0 || y > 7 || y < 0) {
				return false;
			}
			// check if it is on home rows
			if (color == Piece.BLACK) {
				if (x == 7 || x == 0)
					return false;
			}
			if (color == Piece.WHITE) {
				if (y == 7 || y == 0)
					return false;
			}
			// check if it is one of the four corners
			if ((x == 0 && y == 0) || (x == 7 && y == 0) || (x == 0 && y == 7)
					|| (x == 7 && y == 7))
				return false;
			// check if a piece is already there
			if (!board[x][y].isEmpty())
				return false;
			// check if it connects 3 pieces together
			// loop through a square around piece
			int count = 0;
			for (int i = x - 1; i <= x + 1; i++) {
				for (int j = y - 1; j <= y + 1; j++) {
					if (i == x && j == y)
						continue;
					if (i < 0 || i > 7 || j < 0 || j > 7)
						continue;
					Piece p = board[i][j];
					// System.out.println("checking "+i+","+j+" color: "+p.color);
					if (p.color == color) {
						// System.out.println("weee!!"+i+","+j);
						count++;
						if (count > 1) {
							return false;
						}
						// check that piece's surrounding colors.
						for (int ii = p.xpos - 1; ii <= p.xpos + 1; ii++) {
							for (int jj = p.ypos - 1; jj <= p.ypos + 1; jj++) {
								if (ii == p.xpos && jj == p.ypos)
									continue;
								if (ii == x && jj == y)
									continue;
								if (ii < 0 || ii > 7 || jj < 0 || jj > 7)
									continue;
								Piece p2 = board[ii][jj];
								if (p.color == p2.color) {
									// System.out.println("piece found!");
									return false;
								}
							}
						}// end inner double-for
					}// end same-color if
				}
			}

			return true;
		}
	}

	/**
	 * Records a move on the board. An illegal move should NEVER be passed into
	 * this method; always run isLegal beforehand.
	 * 
	 * @param m
	 * @param color
	 */
	public void makeMove(Move m, int color) {
		if (m.moveKind == Move.QUIT) {
			return;
			//throw new RuntimeException("QUIT is not implemented");
		}
		else if (m.moveKind == Move.STEP) {
			if(true){
			//if (isLegal(m, color)) {
				Piece pnew = new Piece(color, m.x1, m.y1);
				Piece old = board[m.x2][m.y2];
				board[m.x1][m.y1] = pnew;
				board[m.x2][m.y2] = Piece.makeEmptyPiece(m.x2, m.y2);
				if (color == Piece.BLACK) {
					blackPieces.remove(old);
					blackPieces.add(pnew);
				} else if (color == Piece.WHITE) {
					whitePieces.remove(old);
					whitePieces.add(pnew);
				}
			} 
			/*
			else {
				throw new RuntimeException("nonlegal move:" + m);
			}*/
		}
		else if (m.moveKind == Move.ADD) {
			if(true){
			//if (isLegal(m, color)) {
				Piece p = new Piece(color, m.x1, m.y1);
				board[m.x1][m.y1] = p;
				if (color == Piece.BLACK) {
					blackPieces.add(p);
				} else if (color == Piece.WHITE) {
					whitePieces.add(p);
				}
			} 
			/*
			else {
				throw new RuntimeException("nonlegal move:" + m);
			}*/
		}
	}

	/**
	 * Clears a tile. (Replaces it with an empty piece)
	 * 
	 * @param x
	 * @param y
	 */
	public void clearSpot(int x, int y) {
		Piece p = board[x][y];
		if (p.color == Piece.BLACK) {
			blackPieces.remove(p);
		} else if (p.color == Piece.WHITE) {
			whitePieces.remove(p);
		}
		board[x][y] = Piece.makeEmptyPiece(x, y);
	}

	public boolean stepTimeWhite() {
		return whitePieces.size() == 10;
	}

	public boolean stepTimeBlack() {
		return blackPieces.size() == 10;
	}

	public boolean equals(Object o) {
		System.out.println("hi");
		if (o instanceof Board) {
			Board other = (Board) o;
			for (int i = 0; i < board[0].length; i++) {
				for (int j = 0; j < board.length; j++) {
					if (other.board[i][j].color != board[i][j].color)
						return false;
				}
			}
			return true;
		} else {
			return false;
		}
	}

	public int hashCode() {
		int hcode = 0;
		for (int i = 0; i < board[0].length; i++) {
			for (int j = 0; j < board.length; j++) {
				Piece p = board[i][j];
				hcode = ((hcode << 5) - hcode) + (p.color);
			}
		}
		return hcode;
	}

	public String toString() {
		StringBuilder sb = new StringBuilder();
		for (int y = 0; y < board.length; y++) {
			for (int x = 0; x < board[0].length; x++) {
				Piece p = board[x][y];
				if (p.color == Piece.BLACK) {
					sb.append("B ");
				} else if (p.color == Piece.WHITE) {
					sb.append("W ");
				} else {
					sb.append("0 ");
				}
			}
			sb.append("\n");
		}
		return sb.toString();
	}
}
